Technical Q&A QA1272
Customizing Component Border Colors


Q: JFrame の背景色を変更したのですが、特定の JComponent だけは、ボーダーが Aqua の標準的なストライプの背景色のままで描画されます。これらを含んでいる JFrame と同じ色にするにはどうしたらよいのでしょうか。

A: Java 1.4.1 では、さまざまな JComponent で、コントロールによって使われずに残された正方形の矩形領域を塗りつぶすために、必要最小限のボーダーをペイントする必要が生じます。たとえば、Aqua では JButton には丸みのある縁が付いていますが、コンポーネントをコンテナに追加するときには、正方形の矩形領域を塗りつぶす必要があります。余分な領域は Aqua のストライプパターンで描画されます。

これを変更するには、単にコンポーネントの背景色を、希望の色に設定します。

    JButton jb = new JButton("Push Me!");
    jb.setBackground(Color.red);

こうすると背景色がコンテナの背景色と混ざり、外見上は正方形のボーダーのない Aqua ボタンになります。

問題が生じるのは、JComboBox など、二次コンポーネントを生成するコンポーネントに関してです。コンテナに埋め込まれた状態では、JComboBox は特殊ボタンとして表示され、同じようにボーダーの問題が生じますが、これは上記の単純な方法で解決できます。しかし、クリックされると、JComboBox は、その JComboBox に設定されている背景色に合わせたメニューを表示します。これは一般に、Aqua でコントロールのボーダーを除去しようとしたときの、デベロッパの希望に沿ったものではありませんでした。

下記のコードは、特に JComboBox に関してこの問題を回避する方法を示しています。この簡単な解決方法では、デフォルトのレンダラの動作を強化するカスタム ListCellRenderer を使用して、カスタムボーダーの背景を Aqua のデフォルトであるストライプの背景に置き換えています。TestRenderer クラスは、JComboBox メニューのセルに設定されたカスタムの背景色をオーバーライドします。ComboBoxOverride クラスは、この機能を説明するためのテスト用のクラスです。



リスト 1. TestRenderer.java

// TestRenderer クラスを使って、ボーダーの背景として設定されているものの上に、
// Aqua のストライプの背景をペーストできる

import javax.swing.*;
import java.awt.*;

public class TestRenderer implements ListCellRenderer {
// オーバーライドしたいオリジナルの ListCellRenderer
    ListCellRenderer std;
    
    public TestRenderer (ListCellRenderer override) {
        if (override == null) {
            throw new NullPointerException(
                "TestRenderer constructor: default renderer is null");
        }
        std = override;   
    }
    
// getListCellRendererComponent のオーバーライド。  
// これは、コンポーネントをペイントする AWT イベントスレッドによって呼び出される 
    public Component getListCellRendererComponent(JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus) {
// 標準のレンダラに、何を正しいと見なしているかを尋ねる
        Component c = std.getListCellRendererComponent(list,
                        value,
                        index,
                        isSelected,
                        cellHasFocus);
        if (!isSelected) {
// 返されたコンポーネントの背景を、Aqua のストライプ付きの背景に設定。ただし、
// 選択されていないセルに対してのみ。
// 標準のレンダラは、ハイライトされているセルに対して、 
// 要求どおりに機能する
            c.setBackground((Color)UIManager.get("ComboBox.background"));
        }
        return c;
    }
}





リスト 2. ComboBoxOverride.java

// TestRenderer の機能を示すためのテストケース

import java.awt.*;
import javax.swing.*;


public class ComboBoxOverride extends JFrame {

    public ComboBoxOverride)( {    
        Color bgColor = Color.red;
        this.getContentPane().setLayout(new BorderLayout());

        this.getContentPane().setBackground(bgColor);
        JButton b = new JButton("Hello");
        JComboBox line = new JComboBox( new Object []{
            "Option One",
            "Option Two",
            "Option Three"});             
// JComboBox レンダラを置き換える。
// TestRenderer はオリジナルのレンダラを手放さない
        line.setRenderer(new TestRenderer(line.getRenderer()));
        b.setBackground(bgColor);
        line.setBackground(bgColor);
        this.getContentPane().add(b, BorderLayout.SOUTH);
        this.getContentPane().add(line, BorderLayout.NORTH);
        
        setSize(320, 240);
        setLocation(500, 500);
        setVisible(true);
    }

     public static void main(String args[]) {
         new ComboBoxOverride(true);
     }

}




[2003 年 7 月 31 日]